# webdriver的封装
# basepage.py模块里面是封装的对元素的操作。例如：查找元素、点击元素、文本输入等等。
import os

from Common import logger
import logging
import time
import datetime
from selenium.webdriver.support.wait import WebDriverWait
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from Common.dir_config import screenshot_dir
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.select import Select
# # 上传文件，操作win系统应用模块
# import win32gui
# import win32con


class BasePage:
    """
        包含了PageObjects当中，用到所有的selenium底层方法。
        还可以包含通用的一些元素操作，如alert,iframe,windows...
        还可以自己额外封装一些web相关的断言
        实现日志记录、实现失败截图
    """

    def __init__(self, driver=None):
        self.driver = driver

    # 初始化driver
    def create_driver(self):
        if not self.driver:
            self.driver = webdriver.Chrome()
            self.driver.maximize_window()
        return self.driver

    # 实现网页截图操作
    def save_web_screenshot(self, img_doc):
        # 页面_功能_时间.png
        now = time.strftime("%Y-%m-%d %H_%M_%S")
        filepath = "{}-{}.png".format(now, img_doc)
        now_date = time.strftime("%Y%m%d")
        screenshot_now_date_dir = os.path.join(os.path.dirname(screenshot_dir), 'screenshots/{}'.format(now_date))
        if not os.path.exists(screenshot_now_date_dir): os.mkdir(screenshot_now_date_dir)  # 如果不存在这个now_date文件夹，就自动创建一个
        try:
            self.driver.save_screenshot(screenshot_now_date_dir + "/" + filepath)
            logging.info("网页截图成功！图片存储在：{}!".format(screenshot_now_date_dir + "/" + filepath))
        except:
            logging.exception("网页截图失败！")
            raise

    # 等待元素可见
    def wait_eleVisible(self, loc, img_doc="", timeout=30, frequency=0.5):
        logging.info("等待元素{}可见！".format(loc))
        if len(loc) > 2:
            loc = (loc[0], loc[1])
        try:
            # 起始等待的时间datetime
            startTime = datetime.datetime.now()
            # 等待元素
            # WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located)
            WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
            # 结束等待时间
            endTime = datetime.datetime.now()
            logging.info("等待元素成功！开始等待时间：{}，结束等待时间：{}，等待时长为：{}！".format(startTime, endTime, endTime - startTime))
        except:
            # 日志
            logging.exception("等待元素可见失败！")
            print("等待 {} 元素可见失败！".format(img_doc))
            # 截图-哪一个页面哪一个操作导致的失败 + 当前时间
            self.save_web_screenshot(img_doc)
            raise

    # toast弹窗
    def toast_wait_eleVisible(self, loc, img_doc="", timeout=2, frequency=0.1):
        logging.info("等待元素{}可见！".format(loc))
        try:
            # 等待元素
            WebDriverWait(self.driver, timeout=timeout,
                          poll_frequency=frequency).until(EC.presence_of_element_located(loc),
                                                          message="{}定位元素未找到".format(img_doc))
            # 截图-哪一个页面哪一个操作导致的失败 + 当前时间
            self.save_web_screenshot(img_doc)
            text = self.get_element_text(loc, img_doc)
            return text
        except:
            # 日志
            logging.exception("等待元素可见失败！")
            print("等待 {} 元素可见失败！".format(img_doc))
            return ""
            # return False
            # raise

    # 查找一个元素
    def get_element(self, loc, img_doc=""):
        """
        :param loc: 元素定位，以元组的形式。（定位类型、定位时间）
        :param img_doc:截图的说明。例如：登录页面_输入用户名
        :return:webElement对象。
        """
        logging.info("查找{}中的元素{}".format(img_doc, loc))
        try:
            if len(loc) > 2:
                ele = self.driver.find_elements(loc[0], loc[1])[loc[2]]
            else:
                ele = self.driver.find_element(*loc)
            logging.info("查找{}元素成功！".format(ele))
            return ele
        except:
            # 日志
            logging.exception("查找元素失败！")
            print("查找 {} 元素失败！".format(img_doc))
            # 截图
            self.save_web_screenshot(img_doc)
            # raise
            return False

    # 等待元素出现，点击元素
    def click_element(self, loc, img_doc, timeout=30, frequency=0.5, sleep_time=1):
        """
        :param loc:元素定位，以元组的形式。（定位类型、定位时间）
        :param img_doc:截图的说明。例如：登录页面_输入用户名
        :param timeout:等待元素的超时上限
        :param frequency:等待元素可见时，轮询周期
        :param sleep_time: 点击元素后等待时间
        :return:
        """
        # 等待元素可见
        self.wait_eleVisible(loc, img_doc, timeout, frequency)
        # 查找元素
        ele = self.get_element(loc, img_doc)
        # 点击操作
        logging.info("点击元素{}！".format(loc))
        try:
            ele.click()
            logging.info("点击元素{}成功！".format(ele))
            time.sleep(sleep_time)
        except:
            # 日志
            logging.exception("点击元素失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 文本输入
    def input_text(self, loc, img_doc, *args):
        """
        等待元素可见，找到元素，并在元素中输入文本信息
        :param loc:元组形式的元素定位表达式
        :param img_doc:执行失败时，截图的文件命名
        :param args:输入操作中，可以输入多个值，也可以组合按键
        :return:
        """
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找元素
        ele = self.get_element(loc, img_doc)
        # 清空输入框内容
        self.clear_data(loc, img_doc)
        # 文本输入
        logging.info("给元素{}输入文本内容：{}".format(loc, *args))
        try:
            ele.send_keys(*args)
            logging.info("文本输入成功！")
        except:
            # 日志
            logging.exception("文本输入失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 获取元素的属性值
    def get_element_attribute(self, loc, attr_name, img_doc):
        """
        获取元素标签的内容
        :param loc:元素定位，以元组的形式。（定位类型、定位时间）
        :param attr_name:属性名称
        :param img_doc:执行失败时，截图的文件命名
        :return:
        """
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找元素
        ele = self.get_element(loc, img_doc)
        # 获取属性
        try:
            attr_value = ele.get_attribute(attr_name)
            logging.info("获取元素{}的属性{}值为：{}！".format(loc, attr_name, attr_value))
            return attr_value
        except:
            # 日志
            logging.exception("获取元素属性失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 获取元素的文本值
    def get_element_text(self, loc, img_doc, timeout=30):
        """
        :param loc:元素定位，以元组的形式。（定位类型、定位时间）
        :param img_doc:执行失败时，截图的文件命名
        :return:
        """
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc, timeout)
        # 查找元素
        ele = self.get_element(loc, img_doc)
        # 获取文本值
        try:
            text = ele.text
            logging.info("获取元素{}的文本值为：{}！".format(loc, text))
            return text
        except:
            # 日志
            logging.exception("获取元素文本值失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 鼠标悬浮操作
    def mouse_suspension(self, loc, img_doc):
        # 实例化ActionChains
        ac = ActionChains(self.driver)
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找元素
        ele = self.get_element(loc)
        # 鼠标悬浮
        try:
            ac.move_to_element(ele).perform()
            time.sleep(1)
            logging.info("鼠标悬浮成功！")
        except:
            # 日志
            logging.exception("鼠标悬浮失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 移动元素到相对位置点击
    def move_relative_position_click(self, loc):
        actions = ActionChains(self.driver)
        print('move_relative_position_click-actions===', actions)
        ele = self.driver.find_elements(*loc)
        print('move_relative_position_click-ele===', ele)
        actions.move_to_element_with_offset(ele, -50, -50)
        actions.click()
        actions.perform()
        print('move_relative_position_click......')

    # 进入到iframe中
    def get_iframe(self, loc, img_doc):
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找元素
        ele = self.get_element(loc)
        # 进入iframe
        try:
            self.driver.switch_to.frame(ele)
            logging.info("进入iframe中成功！")
        except:
            # 日志
            logging.exception("进入到iframe中失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 通过文本选择下拉选择框
    def drop_down_select(self, loc, text, img_doc):
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找select元素
        ele = self.get_element(loc)
        # 下拉选择
        try:
            s = Select(ele)
            s.select_by_visible_text(text)
            # Select(ele.select_by_visible_text(text))
            logging.info("选择select成功！")
        except:
            # 日志
            logging.exception("下拉选择失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 选择非select的下拉选择框
    def drop_down_not_select(self, loc1, loc2, img_doc):
        # 先定位到下拉菜单
        # 等待元素出现
        self.wait_eleVisible(loc1, img_doc)
        # 查找下拉菜单元素
        self.click_element(loc1, "下拉菜单输入框")
        logging.info("查找下拉菜单输入框成功！")
        time.sleep(3)
        # 在对下拉菜单的选项进行选择
        try:
            # 选择下拉菜单选项
            # 等待元素出现
            self.wait_eleVisible(loc2, img_doc)
            self.click_element(loc2, "选择下拉菜单选项")
            time.sleep(0.5)
            logging.info("选择下拉菜单成功！")
        except:
            # 日志
            logging.exception("下拉选择失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 多选非select的下拉选择框
    def drop_down_not_selects(self, loc1, img_doc, *args, submit_loc=None):
        # 先定位到下拉菜单
        # 等待元素出现
        self.wait_eleVisible(loc1, img_doc)
        # 查找下拉菜单元素
        self.click_element(loc1, "下拉菜单输入框")
        logging.info("查找下拉菜单输入框成功！")
        time.sleep(3)
        # 在对下拉菜单的选项进行选择
        try:
            # 选择下拉菜单选项
            # 等待元素出现
            for loc in args:
                self.wait_eleVisible(loc, img_doc)
                self.click_element(loc, "选择下拉菜单选项")
                logging.info("选择下拉菜单成功！")
            self.wait_eleVisible(submit_loc, img_doc)
            self.click_element(submit_loc, "提交")
            logging.info("提交成功！")
        except:
            # 日志
            logging.exception("下拉选择失败！")
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 清空输入框中的内容
    def clear_data(self, loc, img_doc):
        # 等待元素出现
        self.wait_eleVisible(loc, img_doc)
        # 查找一个元素
        ele = self.get_element(loc)
        # 清空输入框
        try:
            ele.clear()
            logging.info("清空输入框成功！")
        except:
            # 日志
            logging.exception("清空输入框失败！")
            print("清空 {} 输入框失败！".format(img_doc))
            # 截图
            self.save_web_screenshot(img_doc)
            raise

    # 通过标签查找
    def tag_find_elements(self, loc):
        eles = self.driver.find_elements(*loc)
        return eles

    # 判断元素是否存在
    def is_element_exist(self, loc):
        try:
            WebDriverWait(self.driver, timeout=30,
                          poll_frequency=1).until(EC.presence_of_element_located(loc),
                                                  message="{}定位元素未找到".format(loc))
            el = self.driver.find_element(*loc)
            flag = el.is_displayed()
        except:
            flag = False
        logging.info("判断元素{}是否存在且可见--{}".format(loc, flag))
        return flag

    # 点击并通过属性值判断选中状态
    def is_click_and_selected(self, loc, img_doc, attribute_name, expectancy_value):
        """
        :param loc: 定位元素
        :param img_doc: 截图名称
        :param attribute_name: 属性名
        :param expectancy_value: 期望得到的属性值
        :return:
        """
        flag = False
        try:
            self.click_element(loc, img_doc)
            ele = self.driver.find_element(*loc)
            attribute_value = ele.get_attribute(attribute_name)
            if expectancy_value in attribute_value:
                flag = True
        except:
            pass
        return flag

    def scroll_page(self):
        js = ""

    # # 上传操作（前提 ：windows上传窗口已经出现。sleep1-2秒等待弹出的出现。）
    # def upload(filePath, browser_type="chrome"):
    #     if browser_type == "chrome":
    #         title = "打开"
    #     else:
    #         title = ""
    #
    #     # 找元素
    #     # 一级窗口"#32770","打开"
    #     dialog = win32gui.FindWindow("#32770", title)
    #     ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, "ComboBoxEx32", None)  # 二级
    #     comboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, "ComboBox", None)  # 三级
    #     # 编辑按钮
    #     edit = win32gui.FindWindowEx(comboBox, 0, 'Edit', None)  # 四级
    #     # 打开按钮
    #     button = win32gui.FindWindowEx(dialog, 0, 'Button', "打开(&O)")  # 四级
    #
    #     # 往编辑当中，输入文件路径.
    #     win32gui.SendMessage(edit, win32con.WM_SETTEXT, None, filePath)  # 发送文件路径
    #     win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)  # 点击打开按

    def upload_file(self, loc, path, img_doc=''):
        # el = self.driver.find_element(*loc)
        el = self.get_element(loc, img_doc)
        el.send_keys(path)

    # 获取 查找元素
    def base_find(self, loc, img_doc, timeout=60, poll=0.5):
        if len(loc) > 2:
            try:
                return WebDriverWait(self.driver, timeout=timeout,
                                     poll_frequency=poll).until(
                    lambda x: self.driver.find_elements(loc[0], loc[1])[loc[2]])
            except IndexError:
                print("定位元素未找到" + str(loc))
                self.save_web_screenshot(img_doc)
        else:
            return WebDriverWait(self.driver, timeout=timeout,
                                 poll_frequency=poll).until(EC.presence_of_element_located(loc),
                                                            message="定位元素未找到" + str(loc))